#include "net_event_manager.h"
#include "retcodes.h"
#include <string.h>

namespace common
{
namespace net
{
#ifdef _MSC_VER
	CNetEventManager::CNetEventManager()
	{
		epoll_fd_ = -1;
		max_fd_count_ = 0;
		event_handler_ = NULL;
		socket_set_.clear();
	}

	CNetEventManager::~CNetEventManager()
	{

	}

	int32_t CNetEventManager::Startup(int32_t max_fd_count)
	{
		if (max_fd_count <= 0)
		{
			return ENETEVENT_START_ILLEGALPARAM;
		}
		max_fd_count_ = max_fd_count;
		event_handler_ = new INetEventHandler*[max_fd_count];
		return ::common::SUCCEED;
	}

	int32_t CNetEventManager::Shutdown()
	{
		epoll_fd_ = -1;
		if (NULL != event_handler_)
		{
			delete[] event_handler_;
			event_handler_ = NULL;
		}
		max_fd_count_ = 0;
		return ::common::SUCCEED;
	}

	int32_t CNetEventManager::RegisterNetEvent(Socket const * const s1, uint32_t events, INetEventHandler* handler)
	{
		int32_t fd = s1->GetListenFD();
		if (fd < 0 || fd >= max_fd_count_)
		{
			return ENETEVENT_REGISTER_INVALID_FD;
		}
		event_handler_[fd] = handler;
		socket_set_.insert(s1->s_);
		return ::common::SUCCEED;
	}

	int32_t CNetEventManager::UnregisterNetEvent(int fd)
	{
		if (fd < 0 || fd >= max_fd_count_)
		{
			return ENETEVENT_UNREGISTER_INVALID_FD;
		}
		event_handler_[fd] = NULL;
		socket_set_.erase(fd);
		return ::common::SUCCEED;
	}

	int32_t CNetEventManager::OnUpdate(time_t timeout)
	{
		FD_ZERO(&all_fd_set_);
		for (std::set<SOCKET>::iterator it = socket_set_.begin(); it != socket_set_.end(); ++it)
		{
			FD_SET(*it, &all_fd_set_);
		}

		TIMEVAL tval;
		tval.tv_sec = 0;
		tval.tv_usec = timeout * 1000;

		int32_t n = select(0, &all_fd_set_, (fd_set*)0, (fd_set*)0, &tval);
		if (n == SOCKET_ERROR)
			return -1;
		std::set<SOCKET> tmp_socket_set_ = socket_set_;
		for (std::set<SOCKET>::iterator it = tmp_socket_set_.begin(); it != tmp_socket_set_.end(); ++it)
		{
			if (FD_ISSET(*it, &all_fd_set_))
			{
				int32_t fd = int32_t(*it);
				INetEventHandler* handler = event_handler_[fd];
				if (NULL == handler)
				{
					continue;
				}
				handler->OnNetEvent(fd, 1);
			}
		}
		return ::common::SUCCEED;
	}
#else
CNetEventManager::CNetEventManager()
{
    epoll_fd_ = -1;
    epoll_events_ = NULL;
    max_fd_count_ = 0;
    event_handler_ = NULL;
}

CNetEventManager::~CNetEventManager()
{
    if (NULL != epoll_events_)
    {
        delete epoll_events_;
        epoll_events_ = NULL;
    }
}

int32_t CNetEventManager::Startup(int32_t max_fd_count)
{
    if (max_fd_count <= 0)
    {
        return ENETEVENT_START_ILLEGALPARAM;
    }
    max_fd_count_ = max_fd_count;
    epoll_fd_ = epoll_create(max_fd_count);
    if (epoll_fd_ == -1)
    {
        return ENETEVENT_EPOLLFD_CREATE_FAIL;
    }
    epoll_events_ = new epoll_event[ max_fd_count ];
    event_handler_ = new INetEventHandler*[ max_fd_count ];
    return ::common::SUCCEED;
}

int32_t CNetEventManager::Shutdown()
{
    close(epoll_fd_);
    epoll_fd_ = -1;
    if (NULL != epoll_events_)
    {
        delete[] epoll_events_;
        epoll_events_ = NULL;
    }
    if (NULL != event_handler_)
    {
        delete[] event_handler_;
        event_handler_ = NULL;
    }
    max_fd_count_ = 0;
    return ::common::SUCCEED;
}

int32_t CNetEventManager::RegisterNetEvent(int fd, uint32_t events, INetEventHandler* handler)
{
    if (fd < 0 || fd >= max_fd_count_)
    {
        return ENETEVENT_REGISTER_INVALID_FD;
    }
    epoll_event ep;
    memset(&ep, 0, sizeof(ep));
    ep.events = events;
    ep.data.fd = fd;
    if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &ep) != 0)
    {
        return ENETEVENT_CTLADD_FAIL;
    }
    event_handler_[ fd ] = handler;
    return ::common::SUCCEED;
}

int32_t CNetEventManager::UnregisterNetEvent(int fd)
{
    if (fd < 0 || fd >= max_fd_count_)
    {
        return ENETEVENT_UNREGISTER_INVALID_FD;
    }
    epoll_event ep;
    memset(&ep, 0, sizeof(ep));
    ep.data.fd = fd;
    ep.data.ptr = NULL;
    if (epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, &ep) != 0)
    {
        return ENETEVENT_CTLDEL_FAIL;
    }
    event_handler_[ fd ] = NULL;
    return ::common::SUCCEED;
}

int32_t CNetEventManager::OnUpdate(time_t timeout)
{
    int n = epoll_wait(epoll_fd_, epoll_events_, max_fd_count_, timeout);
    for (int32_t i = 0; i < n; ++i)
    {
        epoll_event& ep = epoll_events_[ i ];
        INetEventHandler* handler = event_handler_[ ep.data.fd ];
        if (NULL == handler)
        {
            continue;
        }
        handler->OnNetEvent(ep.data.fd, ep.events);
    }
    return ::common::SUCCEED;
}
#endif
}
}
